package cn.yuanqiao.archive.wenjianzhengli.utils;

import cn.hutool.system.SystemUtil;
import cn.yuanqiao.archive.wenjianzhengli.utils.convert.impl.jave.FFmpegMediaFormatConvert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public abstract class FFmpegUtils {

    private static final Logger logger = LoggerFactory.getLogger(FFmpegUtils.class);
    private static final ExecutorService executorService = Executors.newWorkStealingPool();

    public static boolean exe(String... command) {
        boolean flag = false;
        final ProcessBuilder processBuilder = new ProcessBuilder(command);
        Process process = null;
        try {
            logger.info("FFMpeg命令 执行开始 进程信息 " + processBuilder.command());
            // 执行 FFMpeg 命令
            process = processBuilder.start();
            // 获取命令执行的输出信息
            Process finalProcess = process;
            // 写子进程的输出流或输入流出现失败，则可能导致子进程阻塞，甚至产生死锁,所以要异步。
            executorService.execute(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(finalProcess.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        logger.info("FFMpeg命令 " + Thread.currentThread().getName() + "FFMpegLog输出 " + line);
                    }
                } catch (IOException e) {
                    logger.info("FFMpeg命令 " + Thread.currentThread().getName() + "异常信息输出 " + e);
                }
            });
            // 写子进程的输出流或输入流出现失败，则可能导致子进程阻塞，甚至产生死锁，所以要异步。
            executorService.execute(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(finalProcess.getErrorStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        logger.info("FFMpeg命令 " + Thread.currentThread().getName() + "FFMpegLOG输出 " + line);
                    }
                } catch (IOException e) {
                    logger.info("FFMpeg命令 " + Thread.currentThread().getName() + "异常信息输出 " + e);
                }
            });
            // 等待命令执行完成
            final int exitCode = process.waitFor();
            if (exitCode == 0) {
                logger.info("FFMpeg命令 执行完成 正常退出 退出代码 " + exitCode);
                flag = true;
            } else {
                logger.info("FFMpeg命令 执行完成 异常退出 退出代码" + exitCode);
            }
        } catch (IOException | InterruptedException e) {
            logger.error("FFMpeg命令 异常信息", e);
        } finally {
            // 防止没有释放
            if (process != null) {
                process.destroy();
            }
        }
        return flag;
    }

/*     * 输入视频文件路径 或图片路径 音频路径
     * String inputPath = "input.mp4"; input.jpg input.mp3
     * 输出视频文件路径 或图片路径 音频路径
     * String outputPath = "output.mkv"; output.png output.mp3
     **/

    //todo 图片 jpg、jpeg、png、tif、bmp 支持直接互转 raw格式特殊
    public static boolean converterPicture(String ffmpegPath, String inputPath, String outputPath) {
        // -y 同意覆盖不然会一直阻塞 -q 保存质量 不加容易变模糊
        return exe(ffmpegPath, "-y", "-i", inputPath, "-q", "2", outputPath);
    }

    //todo 音频 wma、mp3、aac 支持直接互转
    public static boolean converterAudio(String ffmpegPath, String inputPath, String outputPath) {
        // -y 同意覆盖不然会一直阻塞 -q 保存质量 不加容易变模糊
        return exe(ffmpegPath, "-y", "-i", inputPath, "-q", "2", outputPath);
    }

    //todo 视频 wav、avi、flv、mp4 支持直接互转 mvb、fmvb格式特殊
    public static boolean converterVideo(String ffmpegPath, String inputPath, String outputPath) {
        // -y 同意覆盖不然会一直阻塞 -q 保存质量 不加容易变模糊
        return exe(ffmpegPath, "-y", "-i", inputPath, "-q", "2", outputPath);
    }

    public static boolean converterRaw(String ffmpegPath, String inputPath, String outputPath) {
        // -y 同意覆盖不然会一直阻塞 -q 保存质量 不加容易变模糊
        // rgb24 rgb32 rgb565
        //return exe(ffmpegPath, "-y", "-i", inputPath, "-vcodec", "rawvideo", "-f", "rawvideo", "-pix_fmt", "rgb565", "-q", "2", outputPath);
        return exe(ffmpegPath, "-y", "-i", inputPath, "-vcodec", "png", "-f", "rawvideo", "-pix_fmt", "rgba", "-q", "2", outputPath);
    }

    public static boolean converterMvb(String ffmpegPath, String inputPath, String outputPath) {
        return exe(ffmpegPath, "-y", "-i", inputPath, "-vcodec", "libx264", "-f", "mp4", "-pix_fmt", "yuv420p", "-q", "2", outputPath);
    }

    public static boolean converterFmvb(String ffmpegPath, String inputPath, String outputPath) {
        return exe(ffmpegPath, "-y", "-i", inputPath, "-vcodec", "libx264", "-f", "mp4", "-pix_fmt", "yuv420p", "-q", "2", outputPath);
    }

   /*  * 获取视频000毫秒第一帧的图片
     *
*/
    public static boolean videoCover(String ffmpegPath, String inputPath, String outputPath) {
        //-ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持，-vframes 设置转换多少桢(frame)的视频
        return exe(ffmpegPath, "-ss", "00:00:00.000", "-y", "-i", inputPath, "-vframes", "1", "-q", "75", outputPath);
    }

/*
     * 获取第一帧
     * w 图片宽度
     * h 图片高度
     *
     *
*/

    public static boolean videoCover(String ffmpegPath, String inputPath, String outputPath, int w, int h) {
        //-ss position 搜索到指定的时间 [-]hh:mm:ss[.xxx]的格式也支持，-vframes 设置转换多少桢(frame)的视频
        return exe(ffmpegPath, "-ss", "00:00:00.000", "-y", "-i", inputPath, "-vframes", "1", "-q", "75", "-s", w + "x" + h, outputPath);
    }

 /*    * 截取第n帧视频图片
     *
*/
    public static boolean videoCover(String ffmpegPath, String inputPath, String outputPath, int frameNum, int w, int h) {
        //d:\\ffmpeg\\bin\\ffmpeg -i d:\\test\2.mp4 -vf "select=eq(n\,100)" -vframes 1 d:\\test\\output.jpg
        return exe(ffmpegPath, "-i", inputPath, "-y", "-vf", "\"select=eq(n\\," + frameNum + ")\"", "-vframes", "1", "-q", "2", "-s", w + "x" + h, outputPath);
    }
/*
     * 获取视频所有帧图片
     **/

    public static boolean videoCoverAll(String ffmpegPath, String inputPath, String outputPath) {
        final Path dir = Paths.get(outputPath);
        if (!Files.isDirectory(dir)) {
            return false;
        }
        return exe(ffmpegPath, "-i", inputPath, "-y", "-r", "1/1", "-q", "2", outputPath + "/image-%03d.jpg");
    }

    private static final FFmpegMediaFormatConvert formatConvert = new FFmpegMediaFormatConvert();

    public static File videoCover(File file) {
        String ffmpegPath = new DefaultFFMPEGLocator().getExecutablePath();
        if (SystemUtil.getOsInfo().isWindows()) {
            String workingDirectory = SystemUtil.getUserInfo().getCurrentDir();
            ffmpegPath = Paths.get(workingDirectory, "ffmpeg", "bin", "ffmpeg.exe")
                    .toAbsolutePath().toString();

        }
        String fileParent = file.getParent();
        String name = "imgPreview";
        Path dir = Paths.get(fileParent, name);
        if (!Files.isDirectory(dir)) {
            try {
                Files.createDirectories(dir);
            } catch (IOException e) {
                throw new RuntimeException("自动创建目录失败");
            }
        }
        File outputFile = dir.resolve("preview.jpg").toFile();
 if (outputFile.exists()) {
            return outputFile;
        }

        videoCover(ffmpegPath, file.getAbsolutePath(), outputFile.getAbsolutePath());
        return outputFile;
    }

    public static File converterVideo(File file, String formatName) {
        String ffmpegPath = new DefaultFFMPEGLocator().getExecutablePath();
        if (SystemUtil.getOsInfo().isWindows()) {
            String workingDirectory = SystemUtil.getUserInfo().getCurrentDir();
            ffmpegPath = Paths.get(workingDirectory, "ffmpeg", "bin", "ffmpeg.exe")
                    .toAbsolutePath().toString();
        }

        String fileParent = file.getParent();
        String name = "transitionVideoPrivew";
        Path dir = Paths.get(fileParent, name);
        if (!Files.isDirectory(dir)) {
            try {
                Files.createDirectories(dir);
            } catch (IOException e) {
                throw new RuntimeException("自动创建目录失败");
            }
        }
        File outputFile = dir.resolve("preview.".concat(formatName)).toFile();
        //converterVideo(ffmpegPath, file.getAbsolutePath(), outputFile.getAbsolutePath());
        try {
            formatConvert.convert(UUID.randomUUID(),file, outputFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return outputFile;
    }

    public static File converterPicture(File file, String formatName) {
        String ffmpegPath = new DefaultFFMPEGLocator().getExecutablePath();
        if (SystemUtil.getOsInfo().isWindows()) {
            String workingDirectory = SystemUtil.getUserInfo().getCurrentDir();
            ffmpegPath = Paths.get(workingDirectory, "ffmpeg", "bin", "ffmpeg.exe")
                    .toAbsolutePath().toString();
        }

        String fileParent = file.getParent();
        String name = "transitionPicturePrivew";
        Path dir = Paths.get(fileParent, name);
        if (!Files.isDirectory(dir)) {
            try {
                Files.createDirectories(dir);
            } catch (IOException e) {
                throw new RuntimeException("自动创建目录失败");
            }
        }
        File outputFile = dir.resolve("preview.".concat(formatName)).toFile();
        //converterPicture(ffmpegPath, file.getAbsolutePath(), outputFile.getAbsolutePath());
        try {
            formatConvert.convert(UUID.randomUUID(),file, outputFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return outputFile;
    }
/*

    # rgb8888 -> bmp
    ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb32 -s 640x480 -i fb.raw -f image2 -vcodec bmp fb.bmp

    # rgb565 -> bmp
    ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 640x480 -i fb.raw -f image2 -vcodec bmp fb.bmp

    # bmp -> rgb8888
    ffmpeg -vcodec bmp -i fb.bmp -vcodec rawvideo -f rawvideo -pix_fmt rgb32 fb.raw

    # bmp -> rgb565
    ffmpeg -vcodec bmp -i fb.bmp -vcodec rawvideo -f rawvideo -pix_fmt rgb565 fb.raw

*/


}
